﻿using System;
using System.Collections.Generic;
using System.Net;
using Cysharp.Threading.Tasks;
using Google.Protobuf;
using TEngine;
using UnityEngine;

namespace GameLogic
{
    public class FightLogicOnlineStrategy : FightLogicStrategy
    {
        FightServer m_Server; //  只要玩家是服务器的时候这个才会被初始化
        FightClient m_Client;

        public Dictionary<uint, GameProtocol.FramePlayerSyncData> m_PlayerDatas =
            new Dictionary<uint, GameProtocol.FramePlayerSyncData>();

        Queue<GameProtocol.FrameSyncData> m_WaitToDoFrameBuffer = new Queue<GameProtocol.FrameSyncData>();
        bool m_IsFirstFrame = true;

        Dictionary<int, GameProtocol.FramePlayerSyncData> m_PlayerDataBuffer =
            new Dictionary<int, GameProtocol.FramePlayerSyncData>();

        float m_PreviousDoLogicTime = 0;
        public FightLogicOnlineStrategy()
        {
            m_StrategyType = StrategyType.Online;
        }

        public override void Init()
        {
            GameEvent.AddEventListener(GameEventType.OnOnlineGameStartClicked,OnGameStartClicked);
        }

        public override void Update()
        {
            m_Server?.Update();
            m_Client?.Update();
            if (m_WaitToDoFrameBuffer.Count >
                0 /*&& Time.time - m_PreviousDoLogicTime >( SystemModule.Instance.LogicDelta.ToFloat() /
                    Mathf.Clamp(m_WaitToDoFrameBuffer.Count / 3, 0.2f, 200))*/)
            {
                var frame = m_WaitToDoFrameBuffer.Dequeue();
                DoLogic(frame);
                m_PreviousDoLogicTime = Time.time;
            }
            //Debug.Log("m_WaitToDoFrameBuffer.Count = " + m_WaitToDoFrameBuffer.Count);
        }

        public virtual void Clear()
        {
            if (m_Server != null)
            {
                m_Server.Disconnect();
                // m_Server.Clear();
            }
            else if (m_Client != null)
            {
                m_Client.Disconnect();
            }
        }

        public void CreateClient(GlobalFunction.ClientType type, string ip = "127.0.0.1")
        {
            // 服务器
            if (m_Server != null)
            {
                m_Server.Clear();
                m_Server = null;
            }

            if (m_Client != null)
            {
                m_Client.Clear();
                m_Client = null;
            }

            if (type == GlobalFunction.ClientType.Server)
            {
                m_Server = FightServer.Create();
                ip = "127.0.0.1";
                Debug.Log("create server");
            }

            //  客户端
            System.Net.IPAddress ipAddress = null;
            if (!System.Net.IPAddress.TryParse(ip, out ipAddress))
            {
                Debug.LogError("非法IP地址");
                return;
            }

            m_Client = FightClient.Create();
            if (m_Client == null)
            {
                Debug.LogError("客户端创建失败");
                return;
            }

            try
            {
                m_Client.Init(35664, new System.Net.IPEndPoint(ipAddress, 35665));
            }
            catch (Exception e)
            {
                Debug.Log("服务器连接失败：" + e.ToString());
            }

            m_Client.OnFrameUpdate.AddListener(OnFrameUpdate);
            m_Client.OnFrameSend.AddListener(OnFrameSend);
            m_Client.AddListener(GameProtocol.Protocol.CSMsgId.ConnectRsp, OnConnected);

            Debug.Log("create client");
        }

        public void DisconnectClient()
        {
            Debug.Log("Disconnect");
            if (m_Server != null)
            {
                m_Server.Disconnect();
            }
            else if (m_Client != null)
            {
                m_Client.Disconnect();
            }
        }

        public void OnFrameUpdate(GameProtocol.FrameSyncData frame)
        {
            DoLogic(frame);
        }

        #region Callback

        public void OnFrameSend(GameProtocol.FrameSyncData frame)
        {
            if (m_IsFirstFrame)
            {
                if (!frame.PlayerDatas.ContainsKey(frame.PlayerID))
                    frame.PlayerDatas.Add(frame.PlayerID, null);
                if (frame.PlayerDatas[frame.PlayerID] == null)
                    frame.PlayerDatas[frame.PlayerID] = new GameProtocol.FramePlayerSyncData();
                frame.PlayerDatas[frame.PlayerID].ControlShipID = GetControlShipID();
                m_IsFirstFrame = false;
            }
        }

        void OnConnected(IPEndPoint ip, byte[] data)
        {
            OnShipDriverChanged();
            m_IsFirstFrame = true;
            GameEvent.Send(GameEventType.OnJointedLobby);
        }

        public void OnShipDriverChanged()
        {
            GameProtocol.Protocol.SwitchShipRqrData rqrData = new GameProtocol.Protocol.SwitchShipRqrData();

            rqrData.ShipData = GameDataModule.Instance.GetShipData(GameDataModule.Instance.GetDriveShipIndex());
            ;
            rqrData.MacAddress = GlobalFunction.GetMACAddress();
            rqrData.PlayerID = m_Client.PlayerID;
            m_Client.Send(GameProtocol.Protocol.CSMsgId.SwitchShipRqr, rqrData.ToByteArray());
        }
        void OnGameStartClicked()
        {
            if (m_Server != null)
                m_Server.StartGame();
        }
        public override void OnLogicTime()
        {
        }

        #endregion

        #region private interface

        void DoLogic(GameProtocol.FrameSyncData frame)
        {
            Debug.Log("DoLogic: " + frame.LogicFrameID);
            foreach (var i in frame.PlayerDatas)
            {
                Debug.Log("PlayerID:" + i.Key + ":\n" + i.Value?.Debug());
            }

            foreach (var i in frame.PlayerDatas)
            {
                if (i.Value == null)
                    continue;
                if (!m_PlayerDatas.ContainsKey(i.Key))
                    m_PlayerDatas.Add(i.Key, new GameProtocol.FramePlayerSyncData());

                // 找到玩家控制的船
                if (i.Value.HasControlShipID)
                    m_PlayerDatas[i.Key].ControlShipID = i.Value.ControlShipID;
                var controlShipID = m_PlayerDatas[i.Key].ControlShipID;
                var controlShip = ShipModule.Instance.GetShip(controlShipID);
                if (controlShip == null)
                    continue;

                // 根据指令控制玩家的船
                if (i.Value.HasFire)
                    controlShip.SetFire(i.Value.Fire);

                // 根据指令控制玩家的船
                if (i.Value.HasAimPosX)
                    controlShip.SetAimPos(new Vector2Int(i.Value.AimPosX, i.Value.AimPosY));

                if (i.Value.HasMoveDirX)
                    controlShip.SetMove(new Vector2Int(i.Value.MoveDirX, i.Value.MoveDirY));
                if (i.Value.HasFocusPosX)
                    controlShip.SetFocusPosition(new Vector2Int(i.Value.FocusPosX, i.Value.FocusPosY));
                //controlShip.DoLogic();
            }

            ShipModule.Instance.DoLogic();
            BulletModule.Instance.DoLogic();
            m_OnLogicComplete.Invoke();
        }

        void CheckCurFrame()
        {
            if (m_Client.CurFrame == null)
                m_Client.CurFrame = new GameProtocol.FrameSyncData();
            m_Client.CurFrame.PlayerID = m_Client.PlayerID;
        }

        #endregion

        public void SetPlayerControlShipInstanceID(uint playerID, int instanceID)
        {
            if (!m_PlayerDatas.ContainsKey(playerID))
            {
                m_PlayerDatas.Add(playerID, new GameProtocol.FramePlayerSyncData());
            }

            m_PlayerDatas[playerID].ControlShipID = instanceID;
        }

        public override int GetControlShipID()
        {
            return m_PlayerDatas[m_Client.PlayerID].ControlShipID;
            ;
        }

        public override void SetControlShipID(int value)
        {
            m_PlayerDatas[m_Client.PlayerID].ControlShipID = value;
        }

        public override void OnFireChanged(bool value)
        {
            CheckCurFrame();
            m_Client.CurFrame.SetPlayerFireState(m_Client.PlayerID, value);
        }

        public override void OnAimPositionChanged(Vector2Int pos)
        {
            CheckCurFrame();
            m_Client.CurFrame.SetPlayerAimPosition(m_Client.PlayerID, pos);
        }

        public override void OnFocusPositionChanged(Vector2Int pos)
        {
            CheckCurFrame();
            m_Client.CurFrame.SetPlayerFocusPosition(m_Client.PlayerID, pos);
        }

        public override void OnMoveDirChanged(Vector2Int dir)
        {
            CheckCurFrame();
            m_Client.CurFrame.SetPlayerMoveDir(m_Client.PlayerID, dir);
        }
    }
}